#!/usr/bin/python3
#
# ProBookCrack.py - Conservative Optimization for HP BIOS Tools
#
# Focuses on single-process optimizations since HP tools don't support concurrency well
#

import time
import os
import sys
import subprocess
import tempfile
from pathlib import Path

Version = "1.03 - Conservative Optimization"
Author = "J R Casey Bralla"
Program = "ProBookCrack.py"

StartTime = time.time()

# Configuration
TEMP_DIR = Path(tempfile.gettempdir()) / "ProBookCrack"
TEMP_DIR.mkdir(exist_ok=True)

# Single temp file - reuse to avoid file creation overhead
TEMP_PASSWORD_FILE = TEMP_DIR / "ProBookPassword.bin"

# HP Tools paths
HP_TOOLS = {
    'password_tool': Path(r'C:\SWSetup\SP143621\HPQPswd64.exe'),
    'bios_tool': Path(r'C:\SWSetup\SP143621\BiosConfigUtility.exe')
}

def check_prerequisites():
    """Check if HP tools exist"""
    missing_tools = []
    for name, path in HP_TOOLS.items():
        if not path.exists():
            missing_tools.append(f"{name}: {path}")
    
    if missing_tools:
        print("ERROR: Missing HP tools:")
        for tool in missing_tools:
            print(f"  - {tool}")
        return False
    
    return True

def ExecExternal(command, timeout=25):
    """Optimized single-process external command execution"""
    try:
        # Windows-specific optimizations for single process
        startupinfo = subprocess.STARTUPINFO()
        startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
        startupinfo.wShowWindow = subprocess.SW_HIDE
        
        # Use higher priority for faster execution
        result = subprocess.run(
            command,
            shell=True,
            capture_output=True,
            text=True,
            timeout=timeout,
            startupinfo=startupinfo,
            creationflags=subprocess.CREATE_NO_WINDOW | subprocess.HIGH_PRIORITY_CLASS
        )
        return (result.stdout, result.stderr, result.returncode)
    except subprocess.TimeoutExpired:
        return ("", "TIMEOUT", -1)
    except Exception as e:
        return ("", str(e), -1)

def TestThePassword(password):
    """Optimized single-threaded password testing"""
    
    try:
        # Clean up any existing temp file first
        if TEMP_PASSWORD_FILE.exists():
            try:
                TEMP_PASSWORD_FILE.unlink()
            except:
                pass
        
        # Step 1: Create encrypted password with shorter timeout
        encrypt_cmd = f'"{HP_TOOLS["password_tool"]}" /s /p"{password}" /f"{TEMP_PASSWORD_FILE}"'
        
        stdout, stderr, returncode = ExecExternal(encrypt_cmd, timeout=12)
        
        if "TIMEOUT" in stderr:
            return "Encrypt Timeout"
        
        if returncode != 0:
            return f"Encrypt Error ({returncode})"
        
        # Quick check if file was created
        if not TEMP_PASSWORD_FILE.exists():
            return "No Encrypt File"
        
        # Step 2: Test the password with shorter timeout
        test_cmd = f'"{HP_TOOLS["bios_tool"]}" /NewSetupPasswordFile:"" /CurSetupPasswordFile:"{TEMP_PASSWORD_FILE}"'
        
        stdout, stderr, returncode = ExecExternal(test_cmd, timeout=12)
        
        # Parse results
        if "TIMEOUT" in stderr:
            return "Test Timeout"
        
        output_lower = stdout.lower()
        
        if "invalid" in output_lower or "incorrect" in output_lower:
            return "Invalid"
        elif "updated" in output_lower or "success" in output_lower or "cleared" in output_lower:
            return "*** FOUND THE PASSWORD ***"
        elif returncode != 0:
            return f"Test Error ({returncode})"
        else:
            # Log the actual output for debugging unknown results
            return f"Unknown: {stdout.strip()[:30]}"
            
    except Exception as e:
        return f"Exception: {str(e)[:30]}"

def load_passwords_efficiently(filename, start_from=1):
    """Load passwords with minimal memory overhead"""
    try:
        file_path = Path(filename)
        if not file_path.exists():
            print(f"Error: Password file '{filename}' not found")
            return []
        
        print(f"Loading passwords from {filename}...")
        
        # Count total lines first for progress
        with open(filename, "r", encoding='utf-8', errors='ignore') as f:
            total_lines = sum(1 for line in f)
        
        print(f"Total passwords in file: {total_lines}")
        print(f"Starting from password #{start_from}")
        
        return file_path, total_lines
        
    except Exception as e:
        print(f"Error accessing password file: {e}")
        return None, 0

def create_optimized_batch_tester():
    """Pre-compile command templates for faster execution"""
    encrypt_template = f'"{HP_TOOLS["password_tool"]}" /s /p"{{password}}" /f"{TEMP_PASSWORD_FILE}"'
    test_template = f'"{HP_TOOLS["bios_tool"]}" /NewSetupPasswordFile:"" /CurSetupPasswordFile:"{TEMP_PASSWORD_FILE}"'
    
    return encrypt_template, test_template

def TestPasswordOptimized(password, encrypt_template, test_template):
    """Ultra-optimized password testing with pre-compiled commands"""
    
    try:
        # Clean previous temp file if it exists
        if TEMP_PASSWORD_FILE.exists():
            TEMP_PASSWORD_FILE.unlink()
        
        # Step 1: Encrypt with pre-compiled template
        encrypt_cmd = encrypt_template.format(password=password)
        stdout, stderr, returncode = ExecExternal(encrypt_cmd, timeout=10)
        
        if "TIMEOUT" in stderr:
            return "Encrypt_TO"
        if returncode != 0 or not TEMP_PASSWORD_FILE.exists():
            return "Encrypt_Fail"
        
        # Step 2: Test with pre-compiled template  
        stdout, stderr, returncode = ExecExternal(test_template, timeout=10)
        
        if "TIMEOUT" in stderr:
            return "Test_TO"
        
        output_lower = stdout.lower()
        if "invalid" in output_lower or "incorrect" in output_lower:
            return "Invalid"
        elif "updated" in output_lower or "success" in output_lower or "cleared" in output_lower:
            return "*** FOUND ***"
        elif returncode != 0:
            return f"Error_{returncode}"
        else:
            return "Unknown"
            
    except Exception as e:
        return "Exception"

def main():
    print(f"{Program} {Version}")
    print(f"by {Author}")
    print("=" * 50)
    
    # Check system prerequisites
    if not check_prerequisites():
        sys.exit(1)
    
    # Parse command line arguments
    start_from = 1
    fast_mode = False
    
    if len(sys.argv) > 1:
        arg = sys.argv[1].lower()
        if arg in ["--help", "-h", "?"]:
            print("Usage:")
            print("  ProBookCrack.py [n]       - Start from nth password")
            print("  ProBookCrack.py --fast    - Use optimized fast mode")
            print("  ProBookCrack.py --help    - Show this help")
            print("\nNote: Multi-threading disabled due to HP tool limitations")
            sys.exit()
        elif arg == "--fast":
            fast_mode = True
        else:
            try:
                start_from = int(arg)
            except ValueError:
                print("Invalid argument. Use --help for usage.")
                sys.exit(1)
    
    # File paths
    password_file = "ProBookTestPasswords.txt"
    log_file_path = Path(r"C:\Users\Micro\Documents\ProBookTestPasswordLog.txt")
    
    # Load password file info
    file_path, total_passwords = load_passwords_efficiently(password_file, start_from)
    if not file_path:
        sys.exit(1)
    
    print(f"\nMode: Single-threaded {'FAST' if fast_mode else 'STANDARD'}")
    print(f"Starting from password #{start_from}")
    print("=" * 50)
    
    # Prepare optimized templates if using fast mode
    if fast_mode:
        encrypt_template, test_template = create_optimized_batch_tester()
        print("Using pre-compiled command templates for maximum speed")
    
    # Main testing loop
    found_password = False
    total_tested = 0
    
    # Ensure log directory exists
    log_file_path.parent.mkdir(parents=True, exist_ok=True)
    
    with open(log_file_path, "a", encoding='utf-8') as log_file:
        log_file.write(f"\n--- Session started at {time.strftime('%Y-%m-%d %H:%M:%S')} ---\n")
        
        with open(file_path, "r", encoding='utf-8', errors='ignore') as pwd_file:
            for line_number, password_line in enumerate(pwd_file, 1):
                
                # Skip until we reach start_from
                if line_number < start_from:
                    continue
                
                password = password_line.rstrip('\n\r')
                if not password:  # Skip empty lines
                    continue
                
                total_tested += 1
                test_start = time.time()
                
                # Test the password
                if fast_mode:
                    result = TestPasswordOptimized(password, encrypt_template, test_template)
                else:
                    result = TestThePassword(password)
                
                test_time = time.time() - test_start
                
                # Calculate statistics
                elapsed_time = time.time() - StartTime
                test_rate = total_tested / elapsed_time if elapsed_time > 0 else 0
                
                # Status output
                status = (
                    f"{line_number:6d} | {password:20s} | {result:15s} | "
                    f"{test_time:5.2f}s | Rate: {test_rate:6.2f}/s | "
                    f"ETA: {(total_passwords-line_number)/test_rate/3600:.1f}h"
                )
                
                print(status)
                
                # Log entry
                log_entry = f"{line_number}\t{password}\t{result}\t{test_time:.2f}s\n"
                log_file.write(log_entry)
                
                # Flush log every 10 entries for real-time monitoring
                if total_tested % 10 == 0:
                    log_file.flush()
                
                # Check for success
                if "FOUND" in result:
                    print("\n" + "=" * 60)
                    print(f"*** SUCCESS! PASSWORD FOUND: '{password}' ***")
                    print("=" * 60)
                    print(f"Tests performed: {total_tested}")
                    print(f"Time elapsed: {elapsed_time:.2f} seconds")
                    print(f"Average rate: {test_rate:.2f} passwords/sec")
                    
                    log_file.write(f"*** PASSWORD FOUND: {password} ***\n")
                    found_password = True
                    break
    
    # Cleanup
    try:
        if TEMP_PASSWORD_FILE.exists():
            TEMP_PASSWORD_FILE.unlink()
        TEMP_DIR.rmdir()
    except:
        pass
    
    # Final summary
    if not found_password:
        elapsed_time = time.time() - StartTime
        print(f"\nCompleted {total_tested} password tests")
        print(f"Time elapsed: {elapsed_time:.2f} seconds")
        print(f"Average rate: {total_tested/elapsed_time:.2f} passwords/sec")

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print("\n\nOperation cancelled by user.")
        # Cleanup on exit
        try:
            if TEMP_PASSWORD_FILE.exists():
                TEMP_PASSWORD_FILE.unlink()
        except:
            pass
        sys.exit(0)
    except Exception as e:
        print(f"\nFatal error: {e}")
        sys.exit(1)
